package etcdclient

import (
	"context"
	"fmt"

	"gitee.com/saroeleven/ginrcpv2/log"
	etcdv3 "go.etcd.io/etcd/client/v3"
)

// listen one key update notify
type broadcast func(key, value []byte)

type option etcdv3.OpOption

func (client *etcdClient) WithPrefix() option {
	return option(etcdv3.WithPrefix())
}

// get and watch key
func (client *etcdClient) LoadAndWatchV3(ctx context.Context, key string, update, delete broadcast, opts ...option) error {
	// get initial config
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	etcdOpts := make([]etcdv3.OpOption, len(opts))
	for i, o := range opts {
		etcdOpts[i] = etcdv3.OpOption(o)
	}
	response, err := client.cli.Get(ctx, key, etcdOpts...)
	if err != nil {
		return fmt.Errorf("failed to get initial config: %w", err)
	}

	for _, kv := range response.Kvs {
		update(kv.Key, kv.Value)
	}

	// watch config
	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Errorf("panic in watch config goroutine: %v", r)
			}
		}()
		watchChan := client.cli.Watch(context.TODO(), key, etcdOpts...)
		for resp := range watchChan {
			for _, ev := range resp.Events {
				switch ev.Type {
				case etcdv3.EventTypePut:
					log.Infof(`"%s" put event, value: %s`, ev.Kv.Key, ev.Kv.Value)
					update(ev.Kv.Key, ev.Kv.Value)
				case etcdv3.EventTypeDelete:
					log.Infof(`"%s" delete event`, ev.Kv.Key)
					delete(ev.Kv.Key, nil)
				}
			}
		}
	}()

	return nil
}
